/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __QS_TransactionDownloader_H__
#define __QS_TransactionDownloader_H__

#include <QtCore/QDate>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtCore/QThread>
#include <QtCore/QFile>

#include "Transaction.h"
#include "NetworkSystem.h"

#include <vector>
#include <map>

namespace QSThink
{
	/*
	//
	class TransactionDownloadThread 
	: public QThread
	{
	Q_OBJECT

	public:
	static const int DAY_MAX=32*1024;//about 90 year i think enough for me
	static const int PARALLEL_MAX=12;//


	~TransactionDownloadThread();
	TransactionDownloadThread(int symbol,QDate startDate,QDate endDate);

	void run();
	void getDayTransaction( int symbol,int day);
	protected:
	//remove the day in the days left
	void removeDay( int day );
	protected:
	QNetworkAccessManager* _netAccessMgr;

	//for parallel list is small.
	std::vector<int> _daysRequesting;
	std::vector<QNetworkReply*> _replysRequesting;

	protected:
	//this day date is download or not
	//int _flags[DAY_MAX];//4K for 1024*32 3*32 years more data this life is enough

	int *_daysLeft;//the array ptr
	int _daysLeftCount;//how many days left to download
	int _dayIndex;//inverted start at last

	int _parallelCount;//parallel download number.
	int _symbol;
	int _dayStart;
	int _dayEnd;
	//int _dayPtr;//ptr to days between start and end

	public slots:
	bool replyFinished(QNetworkReply* reply );
	bool OnReadyRead();
	bool slotError( QNetworkReply::NetworkError error );
	void moveDayIndex();
	void saveBytes( int symbol, int day, QByteArray bytes );
	};

	*/
	class TransactionDownloader;

	//download data from public day to yesterday
	class TransactionDownloadTask 
		: public NetworkListener
	{
	public://should keep a downloader pointer?
		TransactionDownloadTask(QString symbol);

	public:
		QString symbol()
		{
			return _symbol;
		}


		QDate startDate();

		QDate endDate();
		
		void setStartDate(QDate dateStart);
		void setEndDate(QDate dateStart);
		
		void setStartEndDate(QDate dateStart,QDate dateEnd);


		void start();
		void addDays( int dayStart, int dayEnd );

		int dayLeftCount(){
			return _dayTransactionsLeft.size();
		}

		int dayDownCount(){
			return _dayTransactionsDownload.size();
		}

		int daysTotal(){
			return _dayTransactionsLeft.size()+_dayTransactionsDownload.size();
		}

		int getLeftDay(int index){
			DayTransactionMap::iterator it=_dayTransactionsLeft.begin();
			DayTransactionMap::iterator itEnd=_dayTransactionsLeft.end();
			for (int i=0;it!=itEnd;++it,++i){
				if(i==index){
					return it->first;
				}
			}
			return -1;
		}

		int getDownDay(int index){
			DayTransactionMap::iterator it=_dayTransactionsDownload.begin();
			DayTransactionMap::iterator itEnd=_dayTransactionsDownload.end();
			for (int i=0;it!=itEnd;++it,++i){
				if(i==index){
					return it->first;
				}
			}
			return -1;
		}

		Transaction1Day* getLeftDayTrans(int index){
			DayTransactionMap::iterator it=_dayTransactionsLeft.begin();
			DayTransactionMap::iterator itEnd=_dayTransactionsLeft.end();
			for (int i=0;it!=itEnd;++it,++i){
				if(i==index){
					return it->second;
				}
			}
			return 0;
		}

		Transaction1Day* getDownDayTrans(int index){
			DayTransactionMap::iterator it=_dayTransactionsDownload.begin();
			DayTransactionMap::iterator itEnd=_dayTransactionsDownload.end();
			for (int i=0;it!=itEnd;++it,++i){
				if(i==index){
					return it->second;
				}
			}
			return 0;
		}



		bool inited(){
			return _started;
		}

	protected:
		void OnNetworkReply(QNetworkReply* reply);
		void persit();

		//check to see whether downloaded is not corrupt
		void checkDownloaded();
	protected:
		QString _symbol;//need downloaded
		int _dayStart;//start to download day
		int _dayEnd;//end to download day
		bool _started;//is this task start download.

		typedef std::map<int,Transaction1Day*> DayTransactionMap;
		typedef std::map<QNetworkReply*,int> NetReplyMap;


		DayTransactionMap _dayTransactionsLeft;
		DayTransactionMap _dayTransactionsDownload;
		NetReplyMap _replies;

		bool _isDownloading;

	};

	class TransactionDownloadListener
	{
	public:
		TransactionDownloadListener();

	protected:
		friend TransactionDownloader;
		virtual void OnDayTransactionDownloaded(Transaction1Day* trans)=0;
		virtual void OnTaskFinished(TransactionDownloadTask* task)=0;

	};

	
	class TransactionDownloader
	{
	public:
		static const QString PersitFileName;
	protected:
		//
		TransactionDownloader();
	public:
		~TransactionDownloader();
		static TransactionDownloader& TransactionDownloader::getSingleton()
		{
			static TransactionDownloader inst;
			return inst;
		}


		int getTaskCount();
		TransactionDownloadTask* getTask(int index);
		TransactionDownloadTask* getTask(QString symbol);

		TransactionDownloadTask* addTask(QString symbol,QDate dateStart,QDate dateEnd);
		

		void persit();
	protected:
		void OnDayTransactionDownloaded(Transaction1Day* trans);
		void OnTaskFinished(TransactionDownloadTask* task);

		std::vector<TransactionDownloadTask*> _tasks;
		friend class TransactionDownloadListener;
		friend class TransactionDownloadTask;
		
		void addListener(TransactionDownloadListener* listener);
		std::vector<TransactionDownloadListener*> _listeners;


	};

}
#endif
